﻿/*************************************************************************************
 * 工    具：  HK_TextCharacterExtractor
 * 
 * 描    述：  本工具用于提取Unity场景中TextMeshPro文本组件的所有唯一字符；
 *             支持TMP_Text（3D文本）和TMP_TextMeshProUGUI（UI文本）类型；
 *             提取结果将保存为单行无换行的UTF-8文本文件，路径为Assets/_UniqueCharacters/[场景名]_AllChars.txt；
 *             本工具适用于字体资源裁剪、字符集管理等需求。
 * 
 * 版    本：  V1.1
 * 作    者：  京产肠饭
 * 
 * 创    建：  2025/05/18  V1.0
 *
 * 更    新：  2025/05/19  V1.1 
 *             1.功能新增：新增可视化编辑器窗口（EditorWindow），支持管理预设字符串（增/删/改），字符提取时整合场景文本与预设字符串的字符（自动去重）
 * 
 * 链    接：  https://gitee.com/JingChanChangFan/hk_-unity-tools
*************************************************************************************/

using UnityEditor;
using UnityEngine;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Reflection;

namespace HKTools
{
    public class HK_TMPCharsExtractor : EditorWindow
    {
        // 预设字符串管理相关变量
        List<string> presetStrings = new List<string>();
        string newStringInput = "";
        Vector2 scrollPos;
        const string prefsKey = "HKTools.TextExtractor.PresetStrings";

        // 菜单项：打开提取工具窗口
        [MenuItem("HKTools/TMP Chars Extractor (TMP文本提取工具)", priority = HK_MenuPriority.HK_TMPCharsExtractor)]
        static void ShowWindow()
        {
            GetWindow<HK_TMPCharsExtractor>("TMP文本提取工具");
        }

        void OnEnable()
        {
            // 加载持久化的预设字符串
            string savedData = EditorPrefs.GetString(prefsKey, "");
            if (!string.IsNullOrEmpty(savedData))
            {
                presetStrings = new List<string>(savedData.Split(new[] { "|##|" }, System.StringSplitOptions.RemoveEmptyEntries));
            }
        }

        void OnGUI()
        {
            EditorGUILayout.Space();

            // 预设字符串管理界面
            GUILayout.Label("预设字符串管理（持久化保存）", EditorStyles.boldLabel);

            EditorGUILayout.Space();

            // 滚动视图显示现有预设
            scrollPos = GUILayout.BeginScrollView(scrollPos);
            for (int i = 0; i < presetStrings.Count; i++)
            {
                GUILayout.BeginHorizontal();
                presetStrings[i] = GUILayout.TextField(presetStrings[i]);
                if (GUILayout.Button("删除", GUILayout.Width(60)))
                {
                    presetStrings.RemoveAt(i);
                    SavePresets(); // 删除后立即保存
                }
                GUILayout.EndHorizontal();
            }
            GUILayout.EndScrollView();

            // 新增预设字符串输入区域
            GUILayout.BeginHorizontal();

            // 修改：移除第二个参数（样式名），使用默认样式
            newStringInput = GUILayout.TextField(newStringInput);

            // 新增：手动绘制提示文本（当输入为空时）
            Rect textFieldRect = GUILayoutUtility.GetLastRect();
            if (string.IsNullOrEmpty(newStringInput))
            {
                GUI.color = Color.gray; // 提示文本设为灰色
                GUI.Label(textFieldRect, "输入新预设字符串");
                GUI.color = Color.white; // 恢复颜色
            }

            if (GUILayout.Button("添加", GUILayout.Width(60)))
            {
                if (!string.IsNullOrEmpty(newStringInput))
                {
                    presetStrings.Add(newStringInput);
                    newStringInput = "";
                    SavePresets(); // 添加后立即保存
                }
            }
            GUILayout.EndHorizontal();

            // 分割线
            EditorGUILayout.Space(10);
            GUILayout.Box("", GUILayout.ExpandWidth(true), GUILayout.Height(1));
            EditorGUILayout.Space(10);

            // 提取操作按钮
            if (GUILayout.Button("执行字符提取（场景+预设）", GUILayout.Height(30)))
            {
                ExtractCharacters(); // 点击按钮触发提取逻辑
            }
        }

        // 保存预设字符串到EditorPrefs
        void SavePresets()
        {
            string dataToSave = string.Join("|##|", presetStrings); // 用特殊分隔符避免冲突
            EditorPrefs.SetString(prefsKey, dataToSave);
        }

        // 核心提取逻辑（整合场景和预设字符）
        void ExtractCharacters()
        {
            if (!IsTextMeshProInstalled())
            {
                HKDebug.LogError("请先从 Package Manager 导入 TextMeshPro 插件！");
                return;
            }

            HashSet<char> uniqueChars = new HashSet<char>();
            var tmpTextType = System.Type.GetType("TMPro.TMP_Text, Unity.TextMeshPro");
            var tmpProUIType = System.Type.GetType("TMPro.TMP_TextMeshProUGUI, Unity.TextMeshPro");

            // 提取场景中的3D文本字符
            if (tmpTextType != null)
            {
                foreach (var tmp in FindObjectsOfType(tmpTextType))
                {
                    string text = tmp.GetType().GetProperty("text").GetValue(tmp, null) as string;
                    if (!string.IsNullOrEmpty(text))
                    {
                        foreach (char c in text)
                        {
                            uniqueChars.Add(c);
                        }
                    }
                }
            }

            // 提取场景中的UI文本字符
            if (tmpProUIType != null)
            {
                foreach (var tmpUI in FindObjectsOfType(tmpProUIType))
                {
                    string text = tmpUI.GetType().GetProperty("text").GetValue(tmpUI, null) as string;
                    if (!string.IsNullOrEmpty(text))
                    {
                        foreach (char c in text)
                        {
                            uniqueChars.Add(c);
                        }
                    }
                }
            }

            // 提取预设字符串中的字符（自动去重）
            foreach (var str in presetStrings)
            {
                if (!string.IsNullOrEmpty(str))
                {
                    foreach (char c in str)
                    {
                        uniqueChars.Add(c);
                    }
                }
            }

            // 保存结果到文件
            if (SaveCharactersToFile(uniqueChars))
            {
                AssetDatabase.Refresh();
                HKDebug.Log($"<color=green>提取完成！</color> 共 {uniqueChars.Count} 个不重复字符，已保存到: {GetRelativePath()}");
            }
            else
            {
                HKDebug.LogError($"<color=red>提取失败！</color> 无法保存文件到: {GetRelativePath()}");
            }
        }

        // ... 原有辅助方法（IsTextMeshProInstalled、SaveCharactersToFile、GetSystemPath、GetRelativePath）保持不变 ...
        static bool IsTextMeshProInstalled()
        {
            Assembly[] assemblies = System.AppDomain.CurrentDomain.GetAssemblies();
            foreach (Assembly assembly in assemblies)
            {
                if (assembly.GetType("TMPro.TMP_Text") != null)
                    return true;
            }
            return false;
        }

        static bool SaveCharactersToFile(HashSet<char> chars)
        {
            try
            {
                string filePath = GetSystemPath();
                string directory = Path.GetDirectoryName(filePath);

                if (!Directory.Exists(directory))
                {
                    Directory.CreateDirectory(directory);
                }

                StringBuilder content = new StringBuilder(chars.Count);

                content.Append('_');

                // 添加26个小写英文字母
                for (char c = 'a'; c <= 'z'; c++)
                {
                    content.Append(c);
                }

                // 添加26个大写英文字母
                for (char c = 'A'; c <= 'Z'; c++)
                {
                    content.Append(c);
                }

                // 遍历提取的字符时检查是否已存在，避免重复
                foreach (char c in chars)
                {
                    // 仅当content中未包含该字符时添加
                    if (!content.ToString().Contains(c))
                    {
                        content.Append(c);
                    }
                }

                File.WriteAllText(filePath, content.ToString(), Encoding.UTF8);
                return File.Exists(filePath);
            }
            catch (System.Exception e)
            {
                HKDebug.LogError($"保存文件时发生异常: {e.Message}");
                return false;
            }
        }

        static string GetSystemPath()
        {
            string sceneName = Path.GetFileNameWithoutExtension(UnityEngine.SceneManagement.SceneManager.GetActiveScene().name);
            return Path.Combine(Application.dataPath, "_UniqueCharacters", $"{sceneName}_AllChars.txt");
        }

        static string GetRelativePath()
        {
            string systemPath = GetSystemPath();
            return "Assets" + systemPath.Replace(Application.dataPath, "");
        }
    }
}